﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using ZerAx.Net;

namespace BlockOS.Server
{
    internal class ConnectManager
    {
        private readonly GameServer server;
        private int incrementIdCounter = 0;
        private readonly List<IConnector> connectors = new();
        private readonly Dictionary<int, IConnection> connections = new();
        private readonly Queue<ConnectMessage> messageQueue = new();

        public Action<int> OnDisconnect { get; set; }
        public ConnectManager(GameServer server)
        {
            this.server = server;
        }

        public void AddConnector(IConnector connector)
        {
            connectors.Add(connector);
            connector.Init();
            if (connector is TcpConnector tcp)
            {
                server.Controller.ResponseTcpListen((IPEndPoint)tcp.listener.LocalEndPoint);
            }
        }

        public void Update()
        {
            // 收集产生的连接
            foreach (var connector in connectors)
            {
                while (connector.TryProduceConnection(out IConnection conn))
                {
                    var id = AddConnection(conn);
                    server.LogMessage($"New connection: {id}");
                }
            }
            // 更新记录的连接，收集已经断开的连接
            var disconnectedIds = new List<int>();
            foreach (var (id, conn) in connections)
            {
                if (!conn.IsConnecting) 
                {
                    disconnectedIds.Add(id);
                    continue;
                }
                conn.Update();
                while (conn.Poll(out var packet))
                {
                    messageQueue.Enqueue(new ConnectMessage
                    {
                        connId = id,
                        packet = packet
                    });
                }
            }
            // 删除断开的连接
            foreach (var id in disconnectedIds)
            {
                server.LogMessage($"conn {id} disconnected.");
                connections.Remove(id);
                OnDisconnect?.Invoke(id);
            }
        }

        public bool Poll(out ConnectMessage? message)
        {
            if (messageQueue.Count > 0)
            {
                message = messageQueue.Dequeue();
                return true;
            }
            message = null;
            return false;
        }

        public void SendPacket(int connId, Packet packet)
        {
            connections[connId].Send(packet);
        }

        public int AddConnection(IConnection connection)
        {
            connections[incrementIdCounter] = connection;
            return incrementIdCounter++;
        }

        public void RemoveConnection(int id)
        {
            connections.Remove(id);
        }

        public void Destory()
        {
            foreach (var connector in connectors)
            {
                connector.Close();
            }
        }

        public struct ConnectMessage
        {
            public int connId;
            public Packet packet;
        }
    }
}
